package com.barunsw.bwf.bims.tool;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;

import com.barunsw.bwf.bims.vo.ChannelHistoryVo;
import com.barunsw.bwf.common.vo.ResultVo;

public class ChannelDataSimulator extends JFrame {
	private static final long serialVersionUID 	= 6578528135050274476L;
	private static Logger LOGGER 				= Logger.getLogger(ChannelDataSimulator.class);
	
	private final int COLUMN_IDX_NAME 		= 0;
	private final int COLUMN_IDX_METHOD 	= 1;
	private final int COLUMN_IDX_URL 		= 2;
	private final int COLUMN_IDX_MIN_VALUE 	= 3;
	private final int COLUMN_IDX_MAX_VALUE 	= 4;
	
	private final String DURATION_TIME_FIVE 		= "5";
	private final String DURATION_TIME_TEN 			= "10";
	private final String DURATION_TIME_FIFTEEN 		= "15";
	private final String DURATION_TIME_TWENTY 		= "20";
	private final String DURATION_TIME_TWENTYFIVE 	= "25";
	private final String DURATION_TIME_THIRTY 		= "30";
	
	private GridBagLayout gridBagLayout = new GridBagLayout();
	
	private JPanel jPanel_Main 		= new JPanel();
	private JPanel jPanel_Output 	= new JPanel();
	private JPanel jPanel_Button 	= new JPanel();
	
	private JTable jTable_Output 			= new JTable();
	private JScrollPane jScrollPane_Output 	= new JScrollPane();
	
	private JLabel jLabel_Duration			= new JLabel("DURATION");
	private JComboBox jComboBox_Duration 	= new JComboBox();
	
	private JToggleButton jToggleButton_Send 	= new JToggleButton("SEND");
	private JButton jButton_Insert 				= new JButton("INSERT");
	private JButton jButton_Save 				= new JButton("SAVE");
	private JButton jButton_Load 				= new JButton("LOAD");
	private JButton jButton_Close 				= new JButton("CLOSE");
	
	private CommonTableModel tableModel;
	
	private Boolean flag = true;
	
	private CloseableHttpClient httpClient;
	
	// JSON 과 JAVA Object 간의 변환을 담당한다.
	private ObjectMapper objectMapper = new ObjectMapper();
	
	// HTTP Request에 대한 결과를 처리한다.
	private ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
		public String handleResponse(final HttpResponse response) 
				throws ClientProtocolException, IOException {
			int status = response.getStatusLine().getStatusCode();
			if (status >= 200 && status < 300) {
				HttpEntity entity = response.getEntity();
				return entity != null ? EntityUtils.toString(entity) : null;
			} 
			else {
				throw new ClientProtocolException("Unexpected response status: " + status);
			}
		}
	};
	
	public ChannelDataSimulator() {
		try {
			initComponent();
			initTable();
			initData();
			initComboBox();
			initAction();
		}
		catch ( Exception ex ) {
			LOGGER.error(ex.getMessage(), ex);
		}
	}
	
	private void initComponent() {
		this.setLayout(gridBagLayout);
		
		jPanel_Main.setLayout(gridBagLayout);
		jPanel_Main.setBackground(Color.white);
		
		jPanel_Output.setLayout(gridBagLayout);
		jPanel_Output.setBackground(Color.white);
		
		jPanel_Button.setLayout(gridBagLayout);
		jPanel_Button.setBackground(Color.white);
		
		jScrollPane_Output.getViewport().add(jTable_Output);
		
		jPanel_Output.add(jScrollPane_Output,
				new GridBagConstraints(0, 0, 1, 1, 
						1.0, 1.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(5, 5, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jLabel_Duration,
				new GridBagConstraints(0, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 5, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jComboBox_Duration,
				new GridBagConstraints(1, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jToggleButton_Send,
				new GridBagConstraints(2, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jButton_Insert,
				new GridBagConstraints(3, 0, 1, 1, 
						1.0, 0.0, 
						GridBagConstraints.EAST, GridBagConstraints.VERTICAL, 
						new Insets(0, 5, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jButton_Save,
				new GridBagConstraints(4, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jButton_Load,
				new GridBagConstraints(5, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 5, 5), 
						0, 0));
		
		jPanel_Button.add(jButton_Close,
				new GridBagConstraints(6, 0, 1, 1, 
						0.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 5, 0), 
						0, 0));
		
		jPanel_Main.add(jPanel_Output,
				new GridBagConstraints(0, 0, 1, 1, 
						1.0, 1.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(5, 5, 5, 5), 
						0, 0));
		
		jPanel_Main.add(jPanel_Button,
				new GridBagConstraints(0, 1, 1, 1, 
						1.0, 0.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 5, 5, 5), 
						0, 0));
		
		this.add(jPanel_Main,
				new GridBagConstraints(0, 0, 1, 1, 
						1.0, 1.0, 
						GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
						new Insets(0, 0, 0, 0), 
						0, 0));
	}
	
	private void initTable() {
		Vector columnVector = new Vector();

		columnVector.addElement("NAME");
		columnVector.addElement("METHOD");
		columnVector.addElement("URL");
		columnVector.addElement("MINIMUM");
		columnVector.addElement("MAXIMUM");

		tableModel = new CommonTableModel(columnVector);

		jTable_Output.setModel(tableModel);
		jTable_Output.setRowHeight(22);
		
		DefaultTableCellRenderer leftTableCellRenderer = new DefaultTableCellRenderer();
		leftTableCellRenderer.setHorizontalAlignment(SwingConstants.LEFT);
		
		DefaultTableCellRenderer rightTableCellRenderer = new DefaultTableCellRenderer();
		rightTableCellRenderer.setHorizontalAlignment(SwingConstants.RIGHT);
		
		int columnCount = jTable_Output.getColumnCount();
		for ( int i = 0; i < columnCount; i++ ) {
			TableColumn tableColumn = jTable_Output.getColumnModel().getColumn(i);

			switch ( i ) {
			case COLUMN_IDX_NAME :
				tableColumn.setPreferredWidth(50);
				tableColumn.setCellRenderer(leftTableCellRenderer);
				break;
			case COLUMN_IDX_METHOD :
				tableColumn.setPreferredWidth(50);
				tableColumn.setCellRenderer(leftTableCellRenderer);
				break;
			case COLUMN_IDX_URL :
				tableColumn.setPreferredWidth(200);
				tableColumn.setCellRenderer(leftTableCellRenderer);
				break;
			case COLUMN_IDX_MIN_VALUE :
				tableColumn.setPreferredWidth(50);
				tableColumn.setCellRenderer(rightTableCellRenderer);
				break;
			case COLUMN_IDX_MAX_VALUE :
				tableColumn.setPreferredWidth(50);
				tableColumn.setCellRenderer(rightTableCellRenderer);
				break;
			}
		}
	}
	
	private void initData() {
		
	}
	
	private void initComboBox() {
		jComboBox_Duration.addItem(DURATION_TIME_FIVE);
		jComboBox_Duration.addItem(DURATION_TIME_TEN);
		jComboBox_Duration.addItem(DURATION_TIME_FIFTEEN);
		jComboBox_Duration.addItem(DURATION_TIME_TWENTY);
		jComboBox_Duration.addItem(DURATION_TIME_TWENTYFIVE);
		jComboBox_Duration.addItem(DURATION_TIME_THIRTY);
	}
	
	private void initAction() {
		jToggleButton_Send.addActionListener(new ChannelDataSimulator_jToggleButton_Send_ActionListener(this));
		jButton_Insert.addActionListener(new ChannelDataSimulator_jButton_Insert_ActionListener(this));
		jButton_Save.addActionListener(new ChannelDataSimulator_jButton_Save_ActionListener(this));
		jButton_Load.addActionListener(new ChannelDataSimulator_jButton_Load_ActionListener(this));
		jButton_Close.addActionListener(new ChannelDataSimulator_jButton_Close_ActionListener(this));
	}
	
	private String getFileName()	{
		Calendar calendar = Calendar.getInstance();
		String pattern = "yyyyMMddHHmmss";
		java.text.DateFormat df = new SimpleDateFormat(pattern, new Locale("ko", "KOREA"));
		String currentTimeStr = df.format(calendar.getTime());

		String fileName = String.format("%s_%s.%s", "VIRTUAL DATA", currentTimeStr, "txt");

		return fileName;
	}
	
	public void jToggleButton_Send_actionPerformed(ActionEvent e) {
		try {
			if ( jToggleButton_Send.isSelected() ) {
				jToggleButton_Send.setText("SENDING...");
				
				flag = true;
			}
			else {
				jToggleButton_Send.setText("SEND");
				
				flag = false;
			}
			
			String duration 		= (String)jComboBox_Duration.getSelectedItem();
			final int requestCycle 	= Integer.parseInt(duration) * 1000;

			Thread requestThread = new Thread(new Runnable() {
				@Override
				public void run() {
					while ( flag ) {
						try {
							Thread.sleep(requestCycle);
						}
						catch ( Exception ex ) {
							ex.printStackTrace();
						}

						try {
							int tableRow = jTable_Output.getRowCount();
							
							for ( int i = 0; i < tableRow; i++ ) {
								String channelId 	= (String)jTable_Output.getValueAt(i, COLUMN_IDX_NAME);
								String minValue 	= (String)jTable_Output.getValueAt(i, COLUMN_IDX_MIN_VALUE);
								String maxValue 	= (String)jTable_Output.getValueAt(i, COLUMN_IDX_MAX_VALUE);
								
								double curVal = Double.parseDouble(minValue) + 
										Math.random() * (Double.parseDouble(maxValue) - Double.parseDouble(minValue));

								LOGGER.debug(String.format("channelId:%s||minValue:%s||maxValue:%s||culValue:%s", 
										channelId, minValue, maxValue, curVal));

								ChannelHistoryVo channelHistoryVo = new ChannelHistoryVo();
								channelHistoryVo.setId(Long.parseLong(channelId));
								channelHistoryVo.setCurVal(curVal);
								
								String data = objectMapper.writeValueAsString(channelHistoryVo);

								LOGGER.debug("data:" + data);

								httpClient = HttpClients.createDefault();

								StringEntity entity = new StringEntity(data, "UTF-8");
								HttpPost httpPost 	= new HttpPost("http://localhost:8080/bwf/channel_history/" + channelId);

								httpPost.addHeader("Content-Type", "application/json");
								httpPost.setEntity(entity);

								LOGGER.debug("httpPost.getURI():" + httpPost.getURI());

								// Create a custom response handler
								String responseBody = httpClient.execute(httpPost, responseHandler);
								ResultVo result 	= new ObjectMapper().readValue(responseBody, ResultVo.class);

								LOGGER.debug(String.format("result:%s", result.getResult()));
							}
						} 
						catch ( Exception ex ) {
							LOGGER.error(ex.getMessage(), ex);
						}
						finally {
							if ( httpClient != null ) {
								try {
									httpClient.close();
								}
								catch ( Exception ex ) {
									ex.printStackTrace();
								}
							}
						}

					}
				}
			});

			requestThread.start();

		}
		catch ( Exception ex ) {
			LOGGER.error(ex.getMessage(), ex);
		}
	}
	
	public void jButton_Insert_actionPerformed(ActionEvent e) {
		ChannelDataInsertPanel channelDataInsertPanel = new ChannelDataInsertPanel();
		
		int confirmValue = JOptionPane.showConfirmDialog(null, channelDataInsertPanel, "", JOptionPane.OK_CANCEL_OPTION);
		
		if ( confirmValue == JOptionPane.OK_OPTION ) {
			Vector<String> dataVector = channelDataInsertPanel.getDataVector();
			
			if ( dataVector != null ) {
				tableModel.addData(dataVector);
				tableModel.fireTableDataChanged();
			}
			else {
				JOptionPane.showMessageDialog(null, "데이터를 입력하세요.", "", JOptionPane.WARNING_MESSAGE);
			}
		}
	}
	
	public void jButton_Save_actionPerformed(ActionEvent e) {
		final int row = jTable_Output.getRowCount();
		
		if ( row > 0 ) {
			final JFileChooser jFileChooser = new JFileChooser();
			jFileChooser.setFileFilter(new FileNameExtensionFilter("TEXT FILES(*.txt)", "txt"));
			jFileChooser.setMultiSelectionEnabled(false);
			
			jFileChooser.setSelectedFile(new File(getFileName()));
		
			int result = jFileChooser.showSaveDialog(this);
			
			if ( result == JFileChooser.APPROVE_OPTION ) {
				Thread thread = new Thread(new Runnable() {
					public void run() {
						BufferedWriter bw = null;
						
						try {
							bw = new BufferedWriter(new FileWriter(jFileChooser.getSelectedFile()));
							bw.write("#BIMS\n");
							bw.write("#NAME,METHOD,URL,MIN,MAX\n");
							
							for ( int i = 0; i < row; i++ ) {
								bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_NAME) + ",");
								bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_METHOD) + ",");
								bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_URL) + ",");
								bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_MIN_VALUE) + ",");
								
								if ( i == row - 1 ) {
									bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_MAX_VALUE) + "");
								}
								else {
									bw.write(jTable_Output.getValueAt(i, COLUMN_IDX_MAX_VALUE) + "\n");
								}
							}
							
							bw.flush();
						}
						catch (Exception ex) {
							ex.printStackTrace();
						}
						finally {
							if ( bw != null ) {
								try {
									bw.close();
								}
								catch ( Exception ex ) {
									ex.printStackTrace();
								}
							}
						}
					}
				});
				
				thread.start();
			}
		}
	}
	
	public void jButton_Load_actionPerformed(ActionEvent e) {
		final JFileChooser jFileChooser = new JFileChooser();
		jFileChooser.setFileFilter(new FileNameExtensionFilter("TEXT FILES(*.txt)", "txt"));
		jFileChooser.setMultiSelectionEnabled(false);
		
		int result = jFileChooser.showOpenDialog(this);
		
		if ( result == JFileChooser.APPROVE_OPTION ) {
			Thread thread = new Thread(new Runnable() {
				public void run() {
					BufferedReader br = null;
					
					try {
						br = new BufferedReader(new FileReader(jFileChooser.getSelectedFile()));
						String readLine = null;
						
						if ( !br.readLine().startsWith("#BIMS") ) {
							JOptionPane.showMessageDialog(null, "불러 올 수 없는 파일입니다.", "", JOptionPane.ERROR_MESSAGE);
							br.close();
							
							return;
						}
						
						while ( (readLine = br.readLine()) != null ) {
							readLine = readLine.trim();
							
							if ( readLine.startsWith("#") || readLine.length() == 0 ) {
								continue;
							}
							else {
								String[] token = readLine.split(",");
								
								Vector oneRowData = new Vector();
								
								oneRowData.addElement(token[0]);
								oneRowData.addElement(token[1]);
								oneRowData.addElement(token[2]);
								oneRowData.addElement(token[3]);
								oneRowData.addElement(token[4]);
								
								tableModel.addData(oneRowData);
								tableModel.fireTableDataChanged();
							}
						}
					}
					catch (Exception ex) {
						ex.printStackTrace();
					}
					finally {
						if ( br != null ) {
							try {
								br.close();
							}
							catch ( Exception ex ) {
								ex.printStackTrace();
							}
						}
					}
				}
			});
			
			thread.start();
		}
	}
	
	public void jButton_Close_actionPerformed(ActionEvent e) {
		int result = JOptionPane.showConfirmDialog(null, "종료하시겠습니까?", "", JOptionPane.OK_CANCEL_OPTION);
		
		if ( result == JOptionPane.OK_OPTION ) {
			flag = false;
			System.exit(0);
		}
	}
	
	public static void main(String[] args) {
		ChannelDataSimulator simulator = new ChannelDataSimulator();
		
		simulator.setTitle("SIMULATOR");
		simulator.setSize(800, 600);
		
		Dimension screenSize 	= Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize 	= simulator.getSize();
		
		simulator.setLocation(screenSize.width / 2 - frameSize.width / 2, screenSize.height / 2 - frameSize.height / 2);
		simulator.setVisible(true);
		simulator.setResizable(false);
		simulator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}

class ChannelDataSimulator_jToggleButton_Send_ActionListener implements ActionListener {
	private ChannelDataSimulator adaptee;
	
	public ChannelDataSimulator_jToggleButton_Send_ActionListener(ChannelDataSimulator adaptee) {
		this.adaptee = adaptee;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		adaptee.jToggleButton_Send_actionPerformed(e);
	}
}

class ChannelDataSimulator_jButton_Insert_ActionListener implements ActionListener {
	private ChannelDataSimulator adaptee;
	
	public ChannelDataSimulator_jButton_Insert_ActionListener(ChannelDataSimulator adaptee) {
		this.adaptee = adaptee;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		adaptee.jButton_Insert_actionPerformed(e);
	}
}

class ChannelDataSimulator_jButton_Save_ActionListener implements ActionListener {
	private ChannelDataSimulator adaptee;
	
	public ChannelDataSimulator_jButton_Save_ActionListener(ChannelDataSimulator adaptee) {
		this.adaptee = adaptee;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		adaptee.jButton_Save_actionPerformed(e);
	}
}

class ChannelDataSimulator_jButton_Load_ActionListener implements ActionListener {
	private ChannelDataSimulator adaptee;
	
	public ChannelDataSimulator_jButton_Load_ActionListener(ChannelDataSimulator adaptee) {
		this.adaptee = adaptee;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		adaptee.jButton_Load_actionPerformed(e);
	}
}

class ChannelDataSimulator_jButton_Close_ActionListener implements ActionListener {
	private ChannelDataSimulator adaptee;
	
	public ChannelDataSimulator_jButton_Close_ActionListener(ChannelDataSimulator adaptee) {
		this.adaptee = adaptee;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		adaptee.jButton_Close_actionPerformed(e);
	}
}